#region Using

using System;
using System.Globalization;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using Jaws.Core.Web.Entities.SiteSettings;

#endregion

namespace Jaws.Core.Web.Controls
{
    /// <summary>
    /// All pages in the custom themes as well as pre-defined pages in the root
    /// must inherit from this class.
    /// </summary>
    /// <remarks>
    /// The class is responsible for assigning the theme to all
    /// derived pages as well as adding RSS, RSD, tracking script
    /// and a whole lot more.
    /// </remarks>
    public abstract class BasePage : Page
    {
        /// <summary>
        /// Adds links and javascript to the HTML header tag.
        /// </summary>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!Page.IsCallback && !Page.IsPostBack)
            {
                // Links
                AddGenericLink("application/rdf+xml", "meta", "SIOC", Utils.AbsoluteWebRoot + "sioc.axd");
                AddGenericLink("application/apml+xml", "meta", "APML", Utils.AbsoluteWebRoot + "apml.axd");
                AddGenericLink("application/rdf+xml", "meta", "FOAF", Utils.AbsoluteWebRoot + "foaf.axd");

                AddGenericLink("application/rss+xml", "alternate", SiteSettings.Instance().SiteName + " (RSS)",
                               Utils.FeedUrl + "?format=rss");
                AddGenericLink("application/atom+xml", "alternate", SiteSettings.Instance().SiteName + " (ATOM)",
                               Utils.FeedUrl + "?format=atom");

                AddGenericLink("application/rsd+xml", "edituri", "RSD", Utils.AbsoluteWebRoot + "rsd.axd");

                AddMetaContentType();

                AddGenericLink("application/opensearchdescription+xml", "search", SiteSettings.Instance().SiteName,
                               Utils.AbsoluteWebRoot + "opensearch.axd");

                AddCustomCodeToHead();

                AddTrackingScript();
            }
            CompressCss();
        }

        /// <summary>
        /// Finds all stylesheets in the header and changes the 
        /// path so it points to css.axd which removes the whitespace.
        /// </summary>
        protected virtual void CompressCss()
        {
            foreach (Control control in Page.Header.Controls)
            {
                var c = control as HtmlControl;
                if (c != null && c.Attributes["type"] != null &&
                    c.Attributes["type"].Equals("text/css", StringComparison.OrdinalIgnoreCase))
                {
                    if (!c.Attributes["href"].StartsWith("http://"))
                    {
                        c.Attributes["href"] = Utils.RelativeWebRoot + "themes/" + SiteSettings.Instance().Theme +
                                               "/css.axd";
                        c.EnableViewState = false;
                    }
                }
            }
        }

        /// <summary>
        /// Adds the content-type meta tag to the header.
        /// </summary>
        protected virtual void AddMetaContentType()
        {
            var meta = new HtmlMeta
                           {
                               HttpEquiv = "content-type",
                               Content = (Response.ContentType + "; charset=" + Response.ContentEncoding.HeaderName)
                           };
            Page.Header.Controls.Add(meta);
        }

        /// <summary>
        /// Add a meta tag to the page's header.
        /// </summary>
        protected virtual void AddMetaTag(string name, string value)
        {
            if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value))
                return;

            var meta = new HtmlMeta {Name = name, Content = value};
            Page.Header.Controls.Add(meta);
        }

        /// <summary>
        /// Adds the generic link to the header.
        /// </summary>
        public virtual void AddGenericLink(string relation, string title, string href)
        {
            var link = new HtmlLink();
            link.Attributes["rel"] = relation;
            link.Attributes["title"] = title;
            link.Attributes["href"] = href;
            Page.Header.Controls.Add(link);
        }

        /// <summary>
        /// Adds the generic link to the header.
        /// </summary>
        public virtual void AddGenericLink(string type, string relation, string title, string href)
        {
            var link = new HtmlLink();
            link.Attributes["type"] = type;
            link.Attributes["rel"] = relation;
            link.Attributes["title"] = title;
            link.Attributes["href"] = href;
            Page.Header.Controls.Add(link);
        }

        /// <summary>
        /// Adds a JavaScript reference to the HTML head tag.
        /// </summary>
        public virtual void AddJavaScriptInclude(string url)
        {
            var script = new HtmlGenericControl("script");
            script.Attributes["type"] = "text/javascript";
            script.Attributes["src"] = ResolveScriptUrl(url);
            Page.Header.Controls.Add(script);
        }

        /// <summary>
        /// Adds a Stylesheet reference to the HTML head tag.
        /// </summary>
        /// <param name="url">The relative URL.</param>
        public virtual void AddStylesheetInclude(string url)
        {
            var link = new HtmlLink();
            link.Attributes["type"] = "text/css";
            link.Attributes["href"] = url;
            link.Attributes["rel"] = "stylesheet";
            Page.Header.Controls.Add(link);
        }

        /// <summary>
        /// Resolves the script URL.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        public virtual string ResolveScriptUrl(string url)
        {
            return Utils.RelativeWebRoot + "js.axd";
        }

        /// <summary>
        /// Adds a JavaScript to the bottom of the page at runtime.    
        /// </summary>
        /// <remarks>
        /// You must add the script tags to the BlogSettings.Instance.TrackingScript.
        /// </remarks>
        protected virtual void AddTrackingScript()
        {
            ClientScript.RegisterStartupScript(GetType(), "tracking", "\n" + SiteSettings.Instance().TrackingScript, false);
        }

        /// <summary>
        /// Adds code to the HTML head section.
        /// </summary>
        protected virtual void AddCustomCodeToHead()
        {
            string code = string.Format(CultureInfo.InvariantCulture,
                                        "{0}<!-- Start custom code -->{0}{1}{0}<!-- End custom code -->{0}",
                                        Environment.NewLine, SiteSettings.Instance().HtmlHeader);
            var control = new LiteralControl(code);
            Page.Header.Controls.Add(control);
        }

        /// <summary>
        /// Translates the specified string using the resource files
        /// </summary>
        public virtual string Translate(string text)
        {
            object resource = GetGlobalResourceObject("labels", text);
            if (resource != null)
                return resource.ToString();

            return string.Format("Missing Resource [{0}]", text);
        }

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.TemplateControl.Error"></see> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
        protected override void OnError(EventArgs e)
        {
            HttpContext ctx = HttpContext.Current;
            Exception exception = ctx.Server.GetLastError();

            if (exception != null && exception.Message.Contains("callback"))
            {
                // This is a robot spam attack so we send it a 404 status to make it go away.
                ctx.Response.StatusCode = 404;
                ctx.Server.ClearError();
            }

            base.OnError(e);
        }
    }
}